package com.jdzy.student.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jdzy.common.constants.CommonConstants;
import com.jdzy.common.constants.RedisConstant;
import com.jdzy.common.constants.ScoreConstants;
import com.jdzy.model.common.dtos.PageRequestDto;
import com.jdzy.model.common.vos.PageResult;
import com.jdzy.model.common.vos.Result;
import com.jdzy.model.student.dtos.GradeDto;
import com.jdzy.model.student.pojos.*;
import com.jdzy.model.student.vos.GradeVo;
import com.jdzy.student.mapper.*;
import com.jdzy.student.service.PkService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static com.jdzy.common.constants.ScoreConstants.COLLEGE_COMPETITION;
import static com.jdzy.common.constants.ScoreConstants.PROVINCIAL_COMPETITION;


@Service
@Slf4j
@RequiredArgsConstructor
public class PkServiceImpl extends ServiceImpl<PkMapper, PkRecord> implements PkService{

//   private final PkMapper pkMapper;
   private final GradeMapper gradeMapper;
   private final CompetitionMapper competitionMapper;
   private final CopyrightMapper copyrightMapper;
   private final PatentMapper patentMapper;
   private final ThesisMapper thesisMapper;
   private final StudentMapper studentMapper;
   @Autowired
//   private RedisTemplate<String,String> redisTemplate;
   private  StringRedisTemplate redisTemplate;

   /**
    * 分页
    *  查询学生排名信息-降序-班级
    * @param stuId
    * @param page
    * @param size
    * @param gradeDto
    * @return
    */
   //此处是根据stuId查询班级内所有学生成绩，然后根据成绩排序
   @Override
   public Result getGradeByStuId(String stuId, Integer page, Integer size, GradeDto gradeDto) {
      //1、检查参数
      if(StringUtils.isBlank(stuId)){
         return Result.error(CommonConstants.PARAM_REQUIRE);
      }
      //设置分页
      PageRequestDto pageRequestDto=new PageRequestDto(page,size);
      pageRequestDto.checkParam();
      //分页查询
      IPage iPage=new Page(pageRequestDto.getPage(),pageRequestDto.getSize());

      // 2、查询班级ID
      Student student = studentMapper.selectOne(
              Wrappers.<Student>lambdaQuery().eq(Student::getStuId, stuId)
      );
      if (student == null) {
         return Result.error("学生基础信息未找到");
      }
      String classroomId = student.getClassroomId();
      // 3. 查询班级内所有学生
      List<Student> studentsInClass = studentMapper.selectList(
              Wrappers.<Student>lambdaQuery().eq(Student::getClassroomId,classroomId)
      );
//      IPage selectPage = studentMapper.selectPage(iPage, Wrappers.<Student>lambdaQuery().eq(Student::getClassroomId, classroomId));
//      List<Student> studentsInClass = selectPage.getRecords();

      if (studentsInClass.isEmpty()) {
         return Result.error("该班级没有学生信息");
      }

      // 4. 收集学生学号
      List<String> studentIds = studentsInClass.stream()
              .map(Student::getStuId)
              .collect(Collectors.toList());

      // 5. 查询所有学生的考试成绩
      List<StudentScore> studentScores = gradeMapper.getScoresByStudentIds(studentIds);

      // 5.1根据学号查询所有学生的姓名
      List<Map<String, String>> studentNameList = studentMapper.getStudentNameByStudentIds(studentIds);
      Map<String, String> nameMap = new HashMap<>();
      for (Map<String, String> map : studentNameList) {
         nameMap.put(map.get("stu_id"), map.get("name"));
         System.out.println(map.get("name"));
      }

      //6.查询所有学生的头像
      List<Map<String, String>> avatarList = studentMapper.getAvatarByStudentIds(studentIds);
      // 创建一个Map来快速查找头像URL
      Map<String, String> avatarMap = new HashMap<>();
      for (Map<String, String> map : avatarList) {
         avatarMap.put(map.get("stu_id"), map.get("avatar"));
      }

      // 7. 查询所有学生的综测成绩
      for (StudentScore score : studentScores) {
         String studentId = score.getStuId();
         //设置头像
         String avatarUrl = avatarMap.get(score.getStuId());
         if (avatarUrl != null) {
            score.setAvatar(avatarUrl);
         }
         //设置姓名
         String name = nameMap.get(score.getStuId());
         if (name != null) {
            score.setName(name);
         }
         // 7.1 查询竞赛信息
         List<Competition> competitions = competitionMapper.getCompetitionsByStudentId(studentId);
         BigDecimal comprehensiveScore = ScoreConstants.INIT;

         for (Competition comp : competitions) {
            if (comp.getAwardLevel() == ScoreConstants.NATIONAL) { // 国家级
               comprehensiveScore = comprehensiveScore.add(ScoreConstants.NATIONAL_COMPETITION);
            } else if (comp.getAwardLevel() == ScoreConstants.PROVINCIAL) { // 省级
               comprehensiveScore = comprehensiveScore.add(PROVINCIAL_COMPETITION);
            } else if (comp.getAwardLevel() == ScoreConstants.COLLEGE) { // 校级
               comprehensiveScore = comprehensiveScore.add(COLLEGE_COMPETITION);
            }
         }

         // 7.2 查询专利信息
         List<Patent> patents = patentMapper.getPatentsByStudentId(studentId);
         if (!patents.isEmpty()) {
            int patentScore = patents.size();
            comprehensiveScore = comprehensiveScore.add(BigDecimal.valueOf(patentScore * ScoreConstants.PATENT));
         }

         // 7.3 查询论文信息
         List<Copyright> papers = copyrightMapper.getCopyrightByStudentId(studentId);
         if (!papers.isEmpty()) {
            int copyrightScore = papers.size();
            comprehensiveScore = comprehensiveScore.add(BigDecimal.valueOf(copyrightScore * ScoreConstants.COPYRIGHT));
         }

         // 7.4 查询课题信息
         List<Thesis> thesis = thesisMapper.getThesisByStudentId(studentId);
         if (!thesis.isEmpty()) {
            int thesisScore = thesis.size();
            comprehensiveScore = comprehensiveScore.add(BigDecimal.valueOf(thesisScore * ScoreConstants.THESIS));
         }

         // 7.5 设置综合分数
         score.setZcScore(comprehensiveScore);
         // 8.将综测分数存入数据库（更新）
         gradeMapper.updateZcScore(score.getStuId(),comprehensiveScore);
      }

      // 8. 计算总分并生成响应对象
      for (StudentScore score : studentScores) {
         BigDecimal examScore = score.getScore();
         BigDecimal comprehensiveScore = score.getZcScore();
         BigDecimal totalScore = examScore.multiply(ScoreConstants.SCORE).add(comprehensiveScore);
         score.setAllScore(totalScore);
         //并且将总分存入数据库（存在就进行更新）
         gradeMapper.updateAllScore(score.getStuId(), totalScore);
      }

      // 9. 按总分降序排序
      List<StudentScore> sortedScores = studentScores.stream()
              .sorted(Comparator.comparing(StudentScore::getAllScore).reversed())
              .collect(Collectors.toList());
      //分页发送给前端
      int startIndex = (pageRequestDto.getPage() - 1) * pageRequestDto.getSize();
      int endIndex = Math.min(startIndex + pageRequestDto.getSize(), sortedScores.size());
      List<StudentScore> paginatedScores = sortedScores.subList(startIndex, endIndex);

      // 设置班级排名并存储到 Redis
      for (StudentScore studentScore : sortedScores) {
         int rank = sortedScores.indexOf(studentScore) + 1; // 获取当前学生的排名
         studentScore.setRank(rank); // 设置排名到对象（可选，如果您后续需要使用这个对象）

         // 生成唯一的 Redis 键，这里使用学生的学号作为唯一标识
         String redisKey = RedisConstant.RANK_CLASS + studentScore.getStuId();

         // 将排名转换为字符串并存储到 Redis
         String rankStr = String.valueOf(rank);
         redisTemplate.opsForValue().set(redisKey, rankStr, RedisConstant.RANK_CLASS_TIME);
      }

      // 创建响应对象
      GradeVo gradeVos = new GradeVo();
      gradeVos.setStudentScores(paginatedScores);

     // 10. 返回结果
//      return Result.success(gradeVo);
      PageResult pageResult=new PageResult(pageRequestDto.getPage(),pageRequestDto.getSize(), (long) sortedScores.size());
      pageResult.setData(gradeVos);
      return pageResult;
   }



   /**
    *   此处是根据stuId分页查询专业内所有学生成绩，然后根据成绩排序
    * @param stuId
    * @param page
    * @param size
    * @param gradeDto
    * @return
    */
   @Override
   public Result getStuIdByProfession(String stuId, Integer page, Integer size, GradeDto gradeDto) {
      //1、检查参数
      if(StringUtils.isBlank(stuId)){
         return Result.error(CommonConstants.PARAM_REQUIRE);
      }
      //设置分页
      PageRequestDto pageRequestDto=new PageRequestDto(page,size);
      pageRequestDto.checkParam();
      //分页查询
      IPage iPage=new Page(pageRequestDto.getPage(),pageRequestDto.getSize());
      // 2、查询专业ID
      Student student = studentMapper.selectOne(
              Wrappers.<Student>lambdaQuery().eq(Student::getStuId, stuId)
      );
      if (student == null) {
         return Result.error("学生基础信息未找到");
      }
      String professionId = student.getProfessionId();
      // 3. 查询专业内所有学生
//      List<Student> studentsInProfession = studentMapper.selectList(
//              Wrappers.<Student>lambdaQuery().eq(Student::getProfessionId,professionId)
//      );
      IPage selectPage = studentMapper.selectPage(iPage,  Wrappers.<Student>lambdaQuery().eq(Student::getProfessionId,professionId));
      List<Student> studentsInProfession = selectPage.getRecords();

      if (studentsInProfession.isEmpty()) {
         return Result.error("该专业没有学生信息");
      }

      // 4. 收集学生学号
      List<String> studentIds = studentsInProfession.stream()
              .map(Student::getStuId)
              .collect(Collectors.toList());

      // 5. 查询所有学生的考试成绩
      List<StudentScore> studentScores = gradeMapper.getScoresByStudentIds(studentIds);

      // 5.1根据学号查询所有学生的姓名
      List<Map<String, String>> studentNameList = studentMapper.getStudentNameByStudentIds(studentIds);
      Map<String, String> nameMap = new HashMap<>();
      for (Map<String, String> map : studentNameList) {
         nameMap.put(map.get("stu_id"), map.get("name"));
         System.out.println(map.get("name"));
      }

      //6.查询所有学生的头像
      List<Map<String, String>> avatarList = studentMapper.getAvatarByStudentIds(studentIds);
      // 创建一个Map来快速查找头像URL
      Map<String, String> avatarMap = new HashMap<>();
      for (Map<String, String> map : avatarList) {
         avatarMap.put(map.get("stu_id"), map.get("avatar"));
      }

      // 7. 查询所有学生的综测成绩
      for (StudentScore score : studentScores) {
         String studentId = score.getStuId();
         //设置头像
         String avatarUrl = avatarMap.get(score.getStuId());
         if (avatarUrl != null) {
            score.setAvatar(avatarUrl);
         }
         //设置姓名
         String name = nameMap.get(score.getStuId());
         if (name != null) {
            score.setName(name);
         }
         // 7.1 查询竞赛信息
         List<Competition> competitions = competitionMapper.getCompetitionsByStudentId(studentId);
         BigDecimal comprehensiveScore = ScoreConstants.INIT;

         for (Competition comp : competitions) {
            if (comp.getAwardLevel() == ScoreConstants.NATIONAL) { // 国家级
               comprehensiveScore = comprehensiveScore.add(ScoreConstants.NATIONAL_COMPETITION);
            } else if (comp.getAwardLevel() == ScoreConstants.PROVINCIAL) { // 省级
               comprehensiveScore = comprehensiveScore.add(PROVINCIAL_COMPETITION);
            } else if (comp.getAwardLevel() == ScoreConstants.COLLEGE) { // 校级
               comprehensiveScore = comprehensiveScore.add(COLLEGE_COMPETITION);
            }
         }

         // 7.2 查询专利信息
         List<Patent> patents = patentMapper.getPatentsByStudentId(studentId);
         if (!patents.isEmpty()) {
            int patentScore = patents.size();
            comprehensiveScore = comprehensiveScore.add(BigDecimal.valueOf(patentScore * ScoreConstants.PATENT));
         }

         // 7.3 查询论文信息
         List<Copyright> papers = copyrightMapper.getCopyrightByStudentId(studentId);
         if (!papers.isEmpty()) {
            int copyrightScore = papers.size();
            comprehensiveScore = comprehensiveScore.add(BigDecimal.valueOf(copyrightScore * ScoreConstants.COPYRIGHT));
         }

         // 7.4 查询课题信息
         List<Thesis> thesis = thesisMapper.getThesisByStudentId(studentId);
         if (!thesis.isEmpty()) {
            int thesisScore = thesis.size();
            comprehensiveScore = comprehensiveScore.add(BigDecimal.valueOf(thesisScore * ScoreConstants.THESIS));
         }


         // 7.5 设置综合分数
         score.setZcScore(comprehensiveScore);
         // 8.将综测分数存入数据库（更新）
         gradeMapper.updateZcScore(score.getStuId(),comprehensiveScore);
      }

      // 8. 计算总分并生成响应对象
      for (StudentScore score : studentScores) {
         BigDecimal examScore = score.getScore();
         BigDecimal comprehensiveScore = score.getZcScore();
         BigDecimal totalScore = examScore.multiply(ScoreConstants.SCORE).add(comprehensiveScore);
         score.setAllScore(totalScore);
         //并且将总分存入数据库（存在就进行更新）
         gradeMapper.updateAllScore(score.getStuId(), totalScore);
      }

// 9. 按总分降序排序
      List<StudentScore> sortedScores = studentScores.stream()
              .sorted(Comparator.comparing(StudentScore::getAllScore).reversed())
              .collect(Collectors.toList());

      //分页发送给前端
      int startIndex = (pageRequestDto.getPage() - 1) * pageRequestDto.getSize();
      int endIndex = Math.min(startIndex + pageRequestDto.getSize(), sortedScores.size());
      List<StudentScore> paginatedScores = sortedScores.subList(startIndex, endIndex);

// 设置专业排名并存储到 Redis
      for (StudentScore studentScore : sortedScores) {
         int rank = sortedScores.indexOf(studentScore) + 1; // 获取当前学生的排名
         studentScore.setRank(rank); // 设置排名到对象（可选，如果您后续需要使用这个对象）

         // 生成唯一的 Redis 键，这里使用学生的学号作为唯一标识
         String redisKey = RedisConstant.RANK_PROFESSION + studentScore.getStuId();

         // 将排名转换为字符串并存储到 Redis
         String rankStr = String.valueOf(rank);
         redisTemplate.opsForValue().set(redisKey, rankStr, RedisConstant.RANK_PROFESSION_TIME);
      }

      // 创建响应对象
      GradeVo gradeVo = new GradeVo();
      gradeVo.setStudentScores(paginatedScores);

//      // 10. 返回结果
//      return Result.success(gradeVo);
      PageResult pageResult=new PageResult(pageRequestDto.getPage(),pageRequestDto.getSize(), (long) sortedScores.size());
      pageResult.setData(gradeVo);
      return pageResult;
   }

   /**
    * 获取pk信息--返回pk输赢结果--细化差距
    * @param stuId1
    * @param stuId2
    * @return
    */
   @Override
   public Result getPkInfo(String stuId1, String stuId2) {
      // 1. 获取两个学生的分数
      StudentScore score1 = gradeMapper.getScoreByStudentId(stuId1);
      StudentScore score2 = gradeMapper.getScoreByStudentId(stuId2);
      if (score1 != null && score2 != null) {
         BigDecimal scoreDiff = score1.getAllScore().subtract(score2.getAllScore());
         if (scoreDiff.compareTo(BigDecimal.ZERO) > 0) {
            // score1 赢了，不返回数据（或者可以返回成功信息）
            return Result.success();
         } else {
            // score1 输了，计算相差的排名、分数和需要提升的考试分数
            int rankDiff = calculateRankDiff(score1, score2);
            BigDecimal examScoreDiffToWin = calculateExamScoreDiffToWin(score1, score2);
            return Result.pk(scoreDiff.abs(), rankDiff, examScoreDiffToWin);
         }
      }
      // 如果没有找到学生信息，返回相应提示
      return Result.error("没有找到学生信息");
   }

   /**
    * 计算两个学生之间的排名差距--排名存到redis中
    * @param score1
    * @param score2
    * @return
    */
   private int   calculateRankDiff( StudentScore score1, StudentScore score2) {
// 检索学生的班级信息
      String stuId1 = score1.getStuId();
      String stuId2 = score2.getStuId();
      // 查询第一个学生的班级信息
      LambdaQueryWrapper<Student> queryWrapper1 = Wrappers.lambdaQuery();
      queryWrapper1.eq(Student::getStuId, stuId1);
      Student student1 = studentMapper.selectOne(queryWrapper1);
      String classId1 = (student1 != null) ? student1.getClassroomId() : null;

// 查询第二个学生的班级信息
      LambdaQueryWrapper<Student> queryWrapper2 = Wrappers.lambdaQuery();
      queryWrapper2.eq(Student::getStuId, stuId2);
      Student student2 = studentMapper.selectOne(queryWrapper2);
      String classId2 = (student2 != null) ? student2.getClassroomId() : null;

      // 判断是否在同一个班级
      boolean sameClass = classId1.equals(classId2);

      // 从Redis中检索排名
      String rankKey1 = sameClass ? RedisConstant.RANK_CLASS + score1.getStuId() : RedisConstant.RANK_PROFESSION + score1.getStuId();
      String rankKey2 = sameClass ? RedisConstant.RANK_CLASS + score2.getStuId() : RedisConstant.RANK_PROFESSION + score2.getStuId();
//重点：在从 Redis 获取值并尝试将其转换为整数之前，先修剪字符串（去除前导和尾随空格）。
      String rankStr1 = redisTemplate.opsForValue().get(rankKey1);
      String rankStr2 = redisTemplate.opsForValue().get(rankKey2);
      int number1= 0;
      int number2= 0;
      if (rankStr1 != null  && rankStr2 != null ) {
         rankStr1 = rankStr1.trim();  // 修剪字符串
         rankStr2 = rankStr2.trim();  // 修剪字符串
         try {
             number1 = Integer.parseInt(rankStr1);
             number2 = Integer.parseInt(rankStr2);
            // 使用 number 进行后续操作
         } catch (NumberFormatException e) {
            // 处理解析错误
            e.printStackTrace();
         }
      }

       //将排名字符串转换为整数
      int rank1 = number1;
      int rank2 = number2;

       //计算排名差
      return Math.abs(rank1 - rank2);
//     return 1;
   }

   /**
    * 计算分数的差距
    * @param score1
    * @param score2
    * @return
    */
   private BigDecimal calculateExamScoreDiffToWin(StudentScore score1, StudentScore score2) {
      BigDecimal totalScoreDiff = score2.getAllScore().subtract(score1.getAllScore()); // 对手总分 - 自己总分
      BigDecimal examScoreNeeded = totalScoreDiff.divide(new BigDecimal(0.7), 2, RoundingMode.HALF_UP); // 需要提升的考试分数
      return examScoreNeeded;
   }
}
